# -*- coding: utf-8 -*-
"""This module contains the controller classes of the application."""

# symbols which are imported by "from cap.controllers import *"
__all__ = ['Root']

import datetime
from turbogears import controllers, expose, flash, redirect, paginate
from model import *
from util import *
from HTMLParser import HTMLParser
from ann import *
from photosvm import *
import thread
import urllib,urllib2



class MyHTMLParser(HTMLParser):
    uid = ''
    img = ''
    in_form = 0
    in_score_tag = 0
    score = 0
    params = {"sel_sex":"female"}
    def handle_starttag(self, tag, attrs):
        attrs = setlist2dict(attrs)
        if tag.lower() == 'form':
            if attrs.get('name','') == 'voteForm':
                self.in_form = 1
        if tag.lower() == 'img':
            if attrs.get('id','') == 'mainPic':
                self.img = attrs['src']
        elif tag.lower() == 'input':
            if self.in_form:
                if attrs.has_key('name') and attrs.has_key('value'):
                    self.params[attrs['name']] = attrs['value']
            if attrs.get('name','') == 'direct_link':
                self.uid = attrs['value'][attrs['value'].index('=')+1:]
        elif tag.lower() == 'div':
            if attrs.get('class','') == 'score':
                self.in_score_tag = 1

    def handle_endtag(self, tag):
        if tag.lower() == 'form':
            if self.in_form:
                self.in_form = 0
        if tag.lower() == 'div':
            if self.in_score_tag:
                self.in_score_tag = 0

    def handle_data(self, data):
        if self.in_score_tag:
            self.score = float(data)


class Root(controllers.RootController):
    """The root controller of the application."""
    crawlerrunning = 0                              #mark if the crawler thread is running
    crawlerprogress = ''
    ann = None
    svm = None

    @expose(template="cap.templates.welcome")
    def index(self, **kw):
        return dict()

    @expose(template="cap.templates.photofilter")   #using a tempate in the templates folder
    @paginate(var_name="photos", limit=50)          #paginate the photos variable, 50 photos a page.
    def photofilter(self, showall=1, **kw):
        if int(showall):
            photos = Photo.query.filter(None).order_by('-time')
        else:
            photos = Photo.query.filter(Photo.test<0).order_by('-time')
        return dict(photos=photos, showall=int(showall), running=self.crawlerrunning, progress=self.crawlerprogress)

    @expose()
    def markasfiltered(self, pid=None, **kw):
        for p in pid:
            Photo.get(int(p)).test = 0
        flush()
        raise redirect('photofilter?showall=0')
        
    @expose()                                       #not using any template.
    def photocrawler(self, amount=0, **kw):
        try:
            self.crawlerrunning = 1
            thread.start_new_thread(self.crawl, (amount,))
            if session.is_active:
                session.commit()
        except Exception, e:
            self.crawlerrunning = 0
            if session.is_active:
                session.rollback()
        raise redirect('photofilter')

    @expose(format="json")                          #return the result dict in JSON format.
    def deletephoto(self, id=None, **kw):
        if not id:
            return dict(deleted=0)
        else:
            p = Photo.get(int(id))
            if p:
                p.destroySelf()
                flush()
            return dict(deleted=1)

    @expose(template="cap.templates.ann")
    def anntrainer(self, **kw):
        return dict(ann=self.ann, nets=AnnNets.query.filter(None).order_by('-time'))

    @expose(template="cap.templates.svm")
    def svmtrainer(self, pid=None, **kw):
        if pid:
            photo = Photo.get_by(uid=pid)
        else:
            photo = None
        return dict(svm=self.svm, photo=photo, nets=SVMNets.query.filter(None).order_by('-time'))

    @expose(format="json")
    def trainann(self, times=0, **kw):
        self.ann.trainNTimes(int(times))
        return dict(epochs=self.ann.times, errorrate=self.ann.errorrate)

    @expose(format="json")
    def trainsvm(self, times=0, **kw):
        if not self.svm:
            return dict(trained=0)
        else:
            self.svm.train()
            return dict(trained=1)

    @expose(format="json")
    def createsvm(self, inputs=0, outputs=0, **kw):
        if not self.svm:
            #self.svm = SVM(Photo.query.filter(Photo.id<2665), int(inputs), int(outputs))
            self.svm = SVM(Photo.query.filter(Photo.test==0), int(inputs), int(outputs))
            self.svm.train()
        return dict(created=1)

    @expose(format="json")
    def createann(self, inputs=0, hidden=0, outputs=0, **kw):
        if not self.ann:
            self.ann = ANN(int(inputs), int(hidden), int(outputs))
            for p in Photo.query.filter(None):
                d = p.genSupervisedDataset()
                self.ann.feed(d[0],d[1])
        return dict(created=1,inputs=self.ann.inputs,hidden=self.ann.hidden,outputs=self.ann.outputs)

    @expose(format="json")
    def loadsvm(self, nid=None, **kw):
        print nid
        return dict(loaded=1)

    @expose(format="json")
    def savesvm(self, filename=None, **kw):
        if not self.svm:
            return dict(saved=0)
        else:
            self.svm.save(filename)
            return dict(saved=1)

    @expose(format="json")
    def predict(self, pid=None, **kw):
        if not self.svm:
            return dict(score=-1)
        p = Photo.get(int(pid))
        score = self.svm.predict(p)[0]
        return dict(score=score)

    @expose(content_type='image/jpeg')              #return the result as a jpg pic
    def getpic(self, id=None, **kw):
        if not id: return ''
        return Photo.get(int(id)).img
    
    @expose(content_type='image/jpeg')
    def getroi(self, id=None, **kw):
        if not id: return ''
        return Photo.get(int(id)).roi

    @expose(content_type='text/html')
    def uploadimg(self, image, **kw):
        p = Photo.createPhoto(image.file)
        if p:
            print p
            raise redirect('svmtrainer?pid='+p)
        else:
            raise redirect('svmtrainer')

    @expose(template="cap.templates.test")
    def test(self,**kw):
        if not self.svm:
            flash("Create a SVM first.")
            raise redirect('svmtrainer')
        i = 0
        #testing = Photo.query.filter(Photo.id>=2665)
        testing = Photo.query.filter(Photo.test==1)
        predictions = {}
        for t in testing:
            s = self.svm.predict(t)[0]
            predictions[t.id] = s
            if round(t.score) == s:
                i += 1
        rate = float(i)/float(testing.count())
        return dict(rate=str(rate),photos=testing,predictions=predictions)
        

    #notice there's no expose here, meaning this function is not accessible from outside world(browser)
    def crawl(self, amount=0):
        uid = ''
        img = ''
        score = 0
        parser = MyHTMLParser()
        baseurl = "http://www.hotornot.com/"
        
        req = urllib2.Request(baseurl)
        html = urllib2.urlopen(req).read()
        parser.feed(html)
        
        imgreq = urllib2.Request(parser.img)
        img = urllib2.urlopen(imgreq).read()
        uid = parser.uid

        dupphotos = []        

        i = 0
        while i != int(amount):
            i += 1
            url = baseurl + '?' + urllib.urlencode(parser.params)
            try:
                req = urllib2.Request(url)
                html = urllib2.urlopen(req).read()
            except:
                return
            parser.feed(html)
            
            score = parser.score    #now we have a score
                
            p = Photo(uid=uid, img=img, score=score)
            flush()
            if not Photo.get_by(uid=uid):
                dupphotos.append(p)
            else:
                try:
                    p.recognize()
                except:
                    pass
            print i, score
                
            imgreq = urllib2.Request(parser.img)
            img = urllib2.urlopen(imgreq).read()
            uid = parser.uid
            self.crawlerprogress = str(i) + '/' + str(amount)
        for p in dupphotos:
            p.destroySelf()
        self.crawlerrunning = 0
        self.crawlerprogress = ''
        return
        
        
        
